package cn.ecpay.unionpay.settle.controller;

import cn.ecpay.unionpay.settle.Common.CommonUtil;
import cn.ecpay.unionpay.settle.Common.DateUtil;
import cn.ecpay.unionpay.settle.Common.RespCode;
import cn.ecpay.unionpay.settle.util.CommonBase;
import cn.ecpay.unionpay.settle.util.FsasService;
import cn.ecpay.unionpay.settle.util.LogUtil;
import cn.ecpay.unionpay.settle.util.SDKConfig;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 批量结算
 * Created by zhaoyanzeng on 2018/11/6.
 */
@RestController
public class BatchFundSettlementController {

    @RequestMapping(value = "/batchFundSettlement", method = RequestMethod.POST)
    public String batchFundSettlement(HttpServletRequest req,MultipartHttpServletRequest multiReq)
            throws ServletException, IOException {

        Map<String, String> contentData = convertContentData(req,multiReq);

        ///对请求参数进行签名并发送http post请求，接收同步应答报文
        Map<String, String> reqData = FsasService.sign(contentData, CommonBase.encoding);            //报文中certId,signature的值是在signData方法中获取并自动赋值的，只要证书配置正确即可。
        String requestBackUrl = SDKConfig.getConfig().getBackRequestUrl();            //交易请求url从配置文件读取对应属性文件fsas_sdk.properties中的 fsassdk.backTransUrl
        Map<String, String> rspData = FsasService.doPost(reqData, requestBackUrl, CommonBase.encoding); //发送请求报文并接受同步应答（默认连接超时时间30秒，读取返回结果超时时间30秒）;这里调用signData之后，调用submitUrl之前不能对submitFromData中的键值对做任何修改，如果修改会导致验签不通过

        //应答码规范参考open.unionpay.com帮助中心 下载  产品接口规范  《平台接入接口规范-第5部分-附录》
        StringBuffer parseStr = new StringBuffer("");
        if (!rspData.isEmpty()) {
            if (FsasService.validate(rspData, CommonBase.encoding)) {
                LogUtil.writeLog("验证签名成功");
                String respCode = rspData.get("respCode");
                if (RespCode.RESP_SUCCESS.equals(respCode)) {
                    //成功
                    //TODO
                } else {
                    //其他应答码为失败请排查原因
                    //TODO
                }
            } else {
                LogUtil.writeErrorLog("验证签名失败");
                //TODO 检查验证签名失败的原因
            }
        } else {
            //未返回正确的http状态
            LogUtil.writeErrorLog("未获取到返回报文或返回http状态码非200");
        }
        String reqMessage = CommonBase.genHtmlResult(reqData);
        String rspMessage = CommonBase.genHtmlResult(rspData);
//        resp.getWriter().write("商户资金结算（批量）请求报文:<br/>" + reqMessage + "<br/>" + "应答报文:</br>" + rspMessage + parseStr);
        return "商户资金结算（批量）请求报文:<br/>" + reqMessage + "<br/>" + "应答报文:</br>" + rspMessage + parseStr;
    }


    /**
     * 批量结算异步通知
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @RequestMapping(value = "/batchFundSettlementNotify", method = RequestMethod.POST)
    public void batchFundSettlementNotify(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        LogUtil.writeLog("批量结算异步通知开始");

        // 获取银联通知服务器发送的后台通知参数
        Map<String, String> reqParam = CommonUtil.getAllRequestParamStream(req);
        LogUtil.printRequestLog(reqParam);

        if (!FsasService.validate(reqParam, CommonBase.encoding)) {
            LogUtil.writeLog("验证签名结果[失败].");

        } else {
            LogUtil.writeLog("验证签名结果[成功].");
            String respCode = reqParam.get("respCode");
            if (RespCode.RESP_SUCCESS.equals(respCode)) {
                //TODO 成功
            } else {
                //TODO 失败
            }
            LogUtil.writeLog("respCode=" + respCode);
        }
        LogUtil.writeLog("批量结算异步通知结束");
    }



    /**
     * 请求数据整理
     *
     * @param req
     * @return
     */
    private Map<String, String> convertContentData(HttpServletRequest req,MultipartHttpServletRequest multiReq) throws FileNotFoundException {

        String filePath = upload(multiReq);

        String acqInsCode = req.getParameter("acqInsCode");
        String batchNo = req.getParameter("batchNo");
        String txnDate = req.getParameter("txnDate");
        String totalAmt = req.getParameter("totalAmt");
        String totalQty = req.getParameter("totalQty");
//        String filePath = req.getParameter("filePath");

        Map<String, String> contentData = new HashMap<String, String>();

        /***银联资金结算接入系统，产品参数，除了encoding自行选择外其他不需修改***/
        contentData.put("version", CommonBase.version);                  //版本号
        contentData.put("encoding", CommonBase.encoding);             //字符集编码 可以使用UTF-8,GBK两种方式
        contentData.put("signMethod", SDKConfig.getConfig().getSignMethod()); //签名方法
        contentData.put("txnType", "21");                                   //21：商户资金结算（批量）
        contentData.put("sndTime", CommonBase.getSendTime());      //发送时间 格式HHmmss
        contentData.put("fileType", "01");                //文件类型01 ：商户资金结算文件
        contentData.put("fileContent", FsasService.enCodeFileContent(filePath, CommonBase.encoding));  //使用DEFLATE压缩算法压缩后，Base64编码的方式传输经压缩编码的文件内容。具体格式参考《平台接口规范-第3部分-文件接口》第4章TXT格式

        contentData.put("batchNo", batchNo);                                    //批次号 机构代码 + 批次  号+交易日期 确定一笔交易
        contentData.put("acqInsCode", acqInsCode);                        //机构代码
        contentData.put("txnDate", txnDate);                               //交易日期
        contentData.put("totalQty", totalQty);                //总笔数 不超过20000
        contentData.put("totalAmt", totalAmt);        //总金额
        contentData.put("backUrl", CommonBase.backUrl);
        return contentData;
    }

    /**
     * 上传结算文件
     * @return 返回文件路径
     * @throws FileNotFoundException
     */
    public String upload(MultipartHttpServletRequest multiReq) throws FileNotFoundException {
        String filePath = "E://settleFile//" + DateUtil.getDateTo8(new Date()) +"/";
        String fileName =  DateUtil.getDateTo14(new Date()) + ".txt";
        File pathFile = new File(filePath);
        if(!pathFile.exists()){
            pathFile.mkdirs();
        }
        FileOutputStream fos=new FileOutputStream(filePath + fileName);
        FileInputStream fs= null;
        byte[] buffer=new byte[1024];
        int len=0;
        try {
            fs=(FileInputStream) multiReq.getFile("fileContext").getInputStream();
            while((len=fs.read(buffer))!=-1){
                fos.write(buffer, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                fos.close();
                fs.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        return filePath + fileName;
    }
}
